package empty.dsa.generator


import chisel3._
import chisel3.util._
class DPM_sha1(elename: String, in_num: Int, PE_num: Int, width: Int) extends Module {

  override val desiredName = elename
  val io = IO(new Bundle() {
    val inputs = Input(Vec(in_num, UInt(width.W)))
    val outputs = Output(Vec(PE_num, UInt(width.W)))
    val cfg = Input(UInt(2.W))
  })
  val DPM_sha1_Ins = Seq.tabulate(PE_num)(i => Module(new sha1_dpm(32, i + 1, PE_num)))

  DPM_sha1_Ins(0).io.cfg := io.cfg(0)
  if(PE_num == 80) {
    DPM_sha1_Ins(0).io.inputs := io.inputs
    DPM_sha1_Ins(0).io.cycle_in := 0.U
  } else {
    when(io.cfg(1) === 1.U) {
      DPM_sha1_Ins(0).io.inputs := io.inputs
      DPM_sha1_Ins(0).io.cycle_in := 0.U
    } .otherwise {
      for (j <- 0 until 16) {
        DPM_sha1_Ins(0).io.inputs(j) := DPM_sha1_Ins(PE_num - 1).io.outputs(j + 1)
        DPM_sha1_Ins(0).io.cycle_in := DPM_sha1_Ins(PE_num - 1).io.cycle_out
      }
    }

  }



  for (i <- 1 until PE_num) {
    for (j <- 0 until 16) {
      DPM_sha1_Ins(i).io.inputs(j) := DPM_sha1_Ins(i - 1).io.outputs(j + 1)
    }
    DPM_sha1_Ins(i).io.cfg := io.cfg(0)
    DPM_sha1_Ins(i).io.cycle_in := DPM_sha1_Ins(i - 1).io.cycle_out
  }

  for (i <- 0 until PE_num) {
    io.outputs(i) := DPM_sha1_Ins(i).io.outputs(0)
  }

}

class sha1_dpm(width: Int, NO_PE: Int, PE_num: Int) extends Module {
  val io = IO(new Bundle() {
    val inputs = Input(Vec(16, UInt(width.W))) //16位作为数据输入
    val cycle_in = Input(UInt(7.W))
    val outputs = Output(Vec(17, UInt(width.W))) //0->pe,2~16->data,17->cycle
    val cycle_out = Output(UInt(7.W))
    val cfg = Input(UInt(1.W))

  })
  val inputsWire = Wire(Vec(16, UInt(width.W)))
  for (i <- 0 until 16) {
    inputsWire(i) := RegNext(io.inputs(i))
  }
  val cycle_in_Wire = Wire(UInt(7.W))

  if (NO_PE == 1) {
    when(io.cfg === 1.U) {
      cycle_in_Wire := 0.U
    }.otherwise {
      cycle_in_Wire := RegNext(io.cycle_in)
    }
  } else {
    cycle_in_Wire := RegNext(io.cycle_in)
  }

  val tmp = inputsWire(13) ^ inputsWire(8) ^ inputsWire(2) ^ inputsWire(0)
  val tmp_data = Cat(tmp(30, 0), tmp(31))

  io.cycle_out := cycle_in_Wire + 1.U

  if (PE_num == 80) {
    if (NO_PE <= 16) {
      io.outputs(0) := inputsWire(0)
      io.outputs(16) := inputsWire(0)
      for (i <- 1 until 16) {
        io.outputs(i) := inputsWire(i)
      }
    } else {
      io.outputs(0) := tmp_data
      io.outputs(16) := tmp_data
      for (i <- 1 until 16) {
        io.outputs(i) := inputsWire(i)
      }
    }
  } else if (PE_num == 40 || PE_num == 20 || PE_num == 16) {
    if (NO_PE <= 16) {
      when(cycle_in_Wire < 16.U) {
        io.outputs(0) := inputsWire(0)
        io.outputs(16) := inputsWire(0)
        for (i <- 1 until 16) {
          io.outputs(i) := inputsWire(i)
        }
      }.otherwise {
        io.outputs(0) := tmp_data
        io.outputs(16) := tmp_data
        for (i <- 1 until 16) {
          io.outputs(i) := inputsWire(i)
        }
      }
    } else {
      io.outputs(0) := tmp_data
      io.outputs(16) := tmp_data
      for (i <- 1 until 16) {
        io.outputs(i) := inputsWire(i)
      }
    }
  } else {
    when(cycle_in_Wire < 16.U) {
      io.outputs(0) := inputsWire(0)
      io.outputs(16) := inputsWire(0)
      for (i <- 1 until 16) {
        io.outputs(i) := inputsWire(i)
      }
    }.otherwise {
      io.outputs(0) := tmp_data
      io.outputs(16) := tmp_data
      for (i <- 1 until 16) {
        io.outputs(i) := inputsWire(i)
      }
    }
  }
}
